package com.googlecode.sparda.commons.lang;

/**
 * Complementary utility to {@link Math}.
 * @author Fabio Grucci (<i>alias</i> <b>Phoenix</b>)
 * @since 1.0
 * @version 1.0
 */
public final class MathUtils {

	private final static String ONE_VALUE_NECESSARY_FOR_CALCULUS = "At least one value is necessary for calculus.";
	
	private MathUtils() {/* Utility class */}
	
	/**
	 * Round the number to the first power of two smaller than the value.
	 * @param number Number to round
	 * @return The biggest power of two smaller than the number
	 */
	public static int roundToExpBaseTwo(double number) {
		return (int) Math.pow(2, Math.getExponent(number));
	}

	/**
	 * Round the number to the first power of two smaller than the value.
	 * @param number Number to round
	 * @return The biggest power of two smaller than the number
	 */
	public static int roundToExpBaseTwo(float number) {
		return (int) Math.pow(2, Math.getExponent(number));
	}

	/**
	 * Methods that return the minimum value of the elements.
	 * @param values The values
	 * @return The minimum value
	 */
	public static byte min(byte... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		byte currentMin = Byte.MIN_VALUE;
		for(byte value : values)
			if(value < currentMin)
				currentMin = value;
		return currentMin;
	}
	
	/**
	 * Methods that return the minimum value of the elements.
	 * @param values The values
	 * @return The minimum value
	 */
	public static short min(short... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		short currentMin = Short.MIN_VALUE;
		for(short value : values)
			if(value < currentMin)
				currentMin = value;
		return currentMin;
	}
	/**
	 * Methods that return the minimum value of the elements.
	 * @param values The values
	 * @return The minimum value
	 */
	public static int min(int... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		int currentMin = Integer.MIN_VALUE;
		for(int value : values)
			if(value < currentMin)
				currentMin = value;
		return currentMin;
	}
	/**
	 * Methods that return the minimum value of the elements.
	 * @param values The values
	 * @return The minimum value
	 */
	public static long min(long... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		long currentMin = Long.MIN_VALUE;
		for(long value : values)
			if(value < currentMin)
				currentMin = value;
		return currentMin;
	}
	/**
	 * Methods that return the minimum value of the elements.
	 * @param values The values
	 * @return The minimum value
	 */
	public static float min(float... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		float currentMin = Float.MIN_VALUE;
		for(float value : values)
			if(value < currentMin)
				currentMin = value;
		return currentMin;
	}
	/**
	 * Methods that return the minimum value of the elements.
	 * @param values The values
	 * @return The minimum value
	 */
	public static double min(double... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		double currentMin = Double.MIN_VALUE;
		for(double value : values)
			if(value < currentMin)
				currentMin = value;
		return currentMin;
	}
	/**
	 * Methods that return the minimum value of the elements.
	 * @param <T> A comparable Type
	 * @param values the values to compare
	 * @return The minimum value
	 */
	public static <T extends Comparable<T>> T min(T... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		T currentMin = values[0];
		for(T value : values)
			if(value.compareTo(currentMin) < 0)
				currentMin = value;
		return currentMin;
	}
	/**
	 * Methods that return the maximum value of the elements.
	 * @param values The values
	 * @return The maximum value
	 */
	public static byte max(byte... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		byte currentMin = Byte.MAX_VALUE;
		for(byte value : values)
			if(value > currentMin)
				currentMin = value;
		return currentMin;
	}
	/**
	 * Methods that return the maximum value of the elements.
	 * @param values The values
	 * @return The maximum value
	 */
	public static short max(short... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		short currentMin = Short.MAX_VALUE;
		for(short value : values)
			if(value > currentMin)
				currentMin = value;
		return currentMin;
	}
	/**
	 * Methods that return the maximum value of the elements.
	 * @param values The values
	 * @return The maximum value
	 */
	public static int max(int... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		int currentMin = Integer.MAX_VALUE;
		for(int value : values)
			if(value > currentMin)
				currentMin = value;
		return currentMin;
	}
	/**
	 * Methods that return the maximum value of the elements.
	 * @param values The values
	 * @return The maximum value
	 */
	public static long max(long... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		long currentMin = Long.MAX_VALUE;
		for(long value : values)
			if(value > currentMin)
				currentMin = value;
		return currentMin;
	}
	/**
	 * Methods that return the maximum value of the elements.
	 * @param values The values
	 * @return The maximum value
	 */
	public static float max(float... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		float currentMin = Float.MAX_VALUE;
		for(float value : values)
			if(value > currentMin)
				currentMin = value;
		return currentMin;
	}
	/**
	 * Methods that return the maximum value of the elements.
	 * @param values The values
	 * @return The maximum value
	 */
	public static double max(double... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		double currentMax = Double.MAX_VALUE;
		for(double value : values)
			if(value > currentMax)
				currentMax = value;
		return currentMax;
	}
	/**
	 * Methods that return the maximum value of the elements.
	 * @param <T> A comparable Type
	 * @param values the values to compare
	 * @return The maximum value
	 */
	public static <T extends Comparable<T>> T max(T... values) {
		if(values.length == 0)
			throw new IllegalArgumentException(ONE_VALUE_NECESSARY_FOR_CALCULUS);
		T currentMax = values[0];
		for(T value : values)
			if(value.compareTo(currentMax) > 0)
				currentMax = value;
		return currentMax;
	}
}
